﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace LunarSF.SHomeWorkshop.LunarMarkdownEditor.Utils
{
    /// <summary>
    /// 银行卡号验证类。
    /// </summary>
    public class _SavingCard
    {
        public static bool Validate(string text)
        {
            if (string.IsNullOrWhiteSpace(text))
                return true;// new ValidationResult(true, null); //银行卡号可以不填。验证OK

            if (text.Length != 19)
                return false;//new ValidationResult(false, "只支持由19位数字构成的银行卡号。"); //验证失败

            //示例银行卡号：623066 5731 000 449499
            //              623066 5731 001 309866


            if (ValidateSavingCardNumber(text))
                return true;// new ValidationResult(true, null); //验证OK
            else
                return false;// new ValidationResult(false, "银行卡号不符合校验规则。"); //验证失败
        }

        /// <summary>
        /// 校验19位银行卡号。
        /// 基本算法如下：
        /// 除去卡号最后一位（这位是校验码），将剩余部分按奇数、偶数位分开；
        /// 奇数位直接求和；
        /// 偶数位如果大于等于5，就先减去5，再乘以2并加1；如果小于5，直接乘以2；
        /// 将偶数位处理过和数字求和；
        /// 将奇数位的总和与偶数位的总和相加，取个位数；
        /// 用10减去取到的个位数就应该是校验码。
        /// =======================================================================
        /// 它的Excel公式表示形式是这样的：
        /// -----------------------------------------------------------------------
        /// =IF(
        ///   MOD(
        ///         10 -RIGHT(
        ///               MID(I222,1,1)+MID(I222,3,1)+MID(I222,5,1)+MID(I222,7,1)+MID(I222,9,1)
        ///                  +MID(I222,11,1)+MID(I222,13,1)+MID(I222,15,1)+MID(I222,17,1)
        ///               +IF(MID(I222,2,1)>="5",(MID(I222,2,1)-5)*2+1,MID(I222,2,1)*2)
        ///               +IF(MID(I222,4,1)>="5",(MID(I222,4,1)-5)*2+1,MID(I222,4,1)*2)
        ///               +IF(MID(I222,6,1)>="5",(MID(I222,6,1)-5)*2+1,MID(I222,6,1)*2)
        ///               +IF(MID(I222,8,1)>="5",(MID(I222,8,1)-5)*2+1,MID(I222,8,1)*2)
        ///               +IF(MID(I222,10,1)>="5",(MID(I222,10,1)-5)*2+1,MID(I222,10,1)*2)
        ///               +IF(MID(I222,12,1)>="5",(MID(I222,12,1)-5)*2+1,MID(I222,12,1)*2)
        ///               +IF(MID(I222,14,1)>="5",(MID(I222,14,1)-5)*2+1,MID(I222,14,1)*2)
        ///               +IF(MID(I222,16,1)>="5",(MID(I222,16,1)-5)*2+1,MID(I222,16,1)*2)
        ///               +IF(MID(I222,18,1)>="5",(MID(I222,18,1)-5)*2+1,MID(I222,18,1)*2),
        ///          1),10)=INT(RIGHT(I222,1)
        ///   ),
        /// "账号正确",IF(LEN(I222)=19,"×××","或为存折"))
        /// ------------------------------------------------------------------------
        /// 用在Excel单元格中作为公式时，需要去除换行和多余的空格。
        /// ========================================================================
        /// </summary>
        /// <param name="savingCardNumberText">银行卡号字符串，只能包括纯数字。</param>
        /// <returns></returns>
        public static bool ValidateSavingCardNumber(string savingCardNumberText)
        {
            if (string.IsNullOrWhiteSpace(savingCardNumberText) || savingCardNumberText.Length != 19) return false;

            var sumOdd = 0;
            var sumEven = 0;
            for (int i = 1; i <= 18; i++)//从1开始好理解些
            {
                if (i % 2 == 1)
                {
                    //奇数位直接相加。
                    int num;
                    if (int.TryParse(savingCardNumberText.Substring(i - 1, 1), out num))
                    {
                        sumOdd += num;
                    }
                    else return false;
                }
                else
                {
                    int num;
                    if (int.TryParse(savingCardNumberText.Substring(i - 1, 1), out num))
                    {
                        if (num >= 5)
                        {
                            sumEven += ((num - 5) * 2 + 1);
                        }
                        else sumEven += (num * 2);
                    }
                    else return false;
                }
            }

            var sum = sumOdd + sumEven;
            int validateCodeNumber;
            if (int.TryParse(savingCardNumberText.Substring(18, 1), out validateCodeNumber) == false) return false;

            var mod = sum % 10;
            if (mod == 0)//取模的值为0时，校验码就应为0。
            {
                return (validateCodeNumber == 0);
            }
            else
            {
                if ((10 - mod) == validateCodeNumber) return true;
            }

            //更简便的写法是：
            //var mod = sum % 10;
            //if ((10 - mod) % 10 == validateCodeNumber) return true;
            //但上面那种更好懂一点。

            return false;
        }

        public static string Format(string origin)
        {
            if (string.IsNullOrWhiteSpace(origin)) return "";
            return origin.Replace(" ", "").Replace("　", "").Replace("\t", "");
        }

        /// <summary>
        /// 判断是否全是汉字。★空字符串返回“false”。
        /// </summary>
        /// <param name="text">源文本。</param>
        /// <returns>如果都在[0x4e00，0x9fbb]范围内，返回真。</returns>
        public static bool AllIsHanChars(string text)
        {
            if (string.IsNullOrWhiteSpace(text)) return false;

            for (int i = 0; i < text.Length; i++)
            {
                if (text[i] >= 0x4e00 && text[i] <= 0x9fbb) continue;
                else return false;
            }

            return true;
        }
    }
}
